#define NFCONF      (*((volatile unsigned long *)0x4E000000))
#define NFCONT      (*((volatile unsigned long *)0x4E000004))
#define NFCMD       (*((volatile unsigned long *)0x4E000008))
#define NFADDR      (*((volatile unsigned long *)0x4E00000C))
#define NFDATA      (*((volatile unsigned char *)0x4E000010))
#define NFSTAT      (*((volatile unsigned long *)0x4E000020))

#define TACLS 1
#define TWRPH0 2
#define TWRPH1 1


void select_chip()
{
    NFCONT &= ~(1<<1);
}

void deselect_chip()
{
    NFCONT |= (1<<1);
}

void clear_RnB()
{
    NFSTAT |= (1<<2);
}

void send_cmd(unsigned cmd)
{
    NFCMD = cmd;
}

void send_addr(unsigned addr)
{
    NFADDR = addr;
}

void wait_RnB()
{
    while(!(NFSTAT & (1<<2))) {
        ;
    }
}

void nand_reset()
{
	/*1.选中nandflash*/
    select_chip();
	
	/*2.清除RB标志位，开启忙信号检测功能*/
    clear_RnB();
	
	/*3.发送0xff复位命令*/
    send_cmd(0xFF);
	
	/*4.等待RnB信号，检测忙信号*/
    wait_RnB();
	
	/*5.取消选中nandflash，为了省电*/
    deselect_chip();
}

void nand_init()
{
	/*1.初始化NFCONF，设置时序参数*/
	NFCONF = ( (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4) );
	
	/*2.初始化NFCONT，取消片选，使能nandflash控制器*/
	NFCONT = (0x3<<0);
	
	/*4.复位操作*/	
	nand_reset();
	
}

void NF_PageRead(unsigned long addr, unsigned char *buff)
{
    int i = 0;
    int page_size = 2048;

    //选中nand flash芯片
    select_chip();

    //清除RnB
    clear_RnB();

    //发送命令0x00
    send_cmd(0x00);

    //发送列地址,两次（但是由于是页读的方式，所以列地址，即页中的偏移量就是0）
    send_addr(0x00);
    send_addr(0x00);

    //发送行地址
    send_addr(addr&0xFF);
    send_addr((addr>>8) & 0xFF);
    send_addr((addr>>16) & 0xFF);

    //发送0x命令30
    send_cmd(0x30);

    //等待RnB
    wait_RnB();

    //读出数据，每次都取出数据寄存器的值，他会自动更新自己的值
	for(i=0; i<page_size; i++) {
		buff[i] = NFDATA;
	}

    //取消选中nand flash芯片
    deselect_chip();
}

void nand_to_ram(unsigned long start_addr, unsigned char *sdram_addr, int size)
{
    int i;
    int page_size = 2048;
    //按页读取
    for( i=(start_addr>>11); size>0; ) {
    NF_PageRead(i, sdram_addr);
    size -= page_size;
    sdram_addr += page_size;
    i++;
    }
}

int nand_erase(unsigned long addr)
{
    int ret;
    //选中nand flash芯片
    select_chip();

    //清除RnB
    clear_RnB();

    //发送命令0x60
    send_cmd(0x60);

    //发送行地址
    send_addr(addr&0xFF);
    send_addr((addr>>8) & 0xFF);
    send_addr((addr>>16) & 0xFF);

    //发送命令0xD0
     send_cmd(0xD0);

    //等待RnB
    wait_RnB();

    //发送命令0x70
    send_cmd(0x70);
    
    //读取擦除结果
    ret = NFDATA;

    //取消选中nand flash芯片
    deselect_chip();

    return ret;
}

int NF_WritePage(unsigned long addr, unsigned char *buff)
{
    int ret;
    int i;
    int page_size = 2048;
    //选中nand flash芯片
    select_chip();

    //清除RnB
    clear_RnB();

    //发送命令0x80
    send_cmd(0x80);

    //发送列地址,两次（但是由于是页读的方式，所以列地址，即页中的偏移量就是0）
    send_addr(0x00);
    send_addr(0x00);

    //发送行地址
    send_addr(addr&0xFF);
    send_addr((addr>>8) & 0xFF);
    send_addr((addr>>16) & 0xFF);

    //写入数据
	for(i=0; i<page_size; i++) {
		NFDATA = buff[i];
	}

    //发送命令0x10
    send_cmd(0x10);
    
    //等待RnB
    wait_RnB();

    //发送命令0x70
    send_cmd(0x70);
    
    //读取写入结果
    ret = NFDATA;

    //取消选中nand flash芯片
    deselect_chip();

    return ret;
}

